package mya.mes.mdc.logic.plc;

import mya.common.jpa.context.ServiceContext;
import mya.common.util.Utils;
import mya.mes.mdc.logic.tag2.ExcelTagAlarmDef;
import mya.mes.mdc.model.plc.PlcTagDef;
import mya.mes.mdc.share.api.MdcModule;
import mya.mes.mdc.share.vo.MdcOptions;

import javax.persistence.criteria.CriteriaBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

public abstract class PlcTagDefUpdater<T extends PlcTagDef> {


    private Class<T> clz;

    public PlcTagDefUpdater(Class<T> clz) {
        this.clz = clz;
    }

    public void update(ServiceContext context, List<ExcelTagAlarmDef> tagAlarmDefList) throws Exception {

        MdcOptions mdcOptions = MdcModule.getInstance().getMdcOptions();

        List<T> dbList = loadAll(context);

        if (Utils.isNullOrEmpty(tagAlarmDefList)) {

            if (Utils.isNullOrEmpty(dbList)) {
                return;
            }

            for (T plcTagType : dbList) {
                plcTagType.setActive(Boolean.FALSE);
            }

            return;
        }

        TreeMap<Long, T> dbMap = new TreeMap<>();

        for (T dbPlcTagType : dbList) {
            dbMap.put(dbPlcTagType.getObjectId(), dbPlcTagType);
        }

        List<T> list = build(mdcOptions, tagAlarmDefList);
        try {
            for (T plcTagType : list) {
                T dbPlcTagType = dbMap.get(plcTagType.getObjectId());

                if (dbPlcTagType != null) {
                    //更新
                    copySrcToDest(plcTagType, dbPlcTagType);

                    updateArea(mdcOptions, plcTagType);
                    processUpdate(mdcOptions, dbPlcTagType);
                    dbMap.remove(plcTagType.getObjectId());
                } else {
                    //新增
                    context.em.persist(plcTagType);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


        dbMap.values().forEach(dbPlcTagType -> {
            dbPlcTagType.setActive(Boolean.FALSE);
        });

    }

    protected void copySrcToDest(T src, T dest) {

        dest.setEnUs(src.getEnUs());

        dest.setZhCN(src.getZhCN());
    }


    private List<T> loadAll(ServiceContext context) {
        String sql = "select o from " + clz.getSimpleName() + " o ";
        CriteriaBuilder cb =
                context.em.getCriteriaBuilder();

        List<T> list =
                context.em.createQuery(sql, clz).getResultList();

        return list;
    }


    private List<T> build(MdcOptions mdcOptions, List<ExcelTagAlarmDef> tagAlarmDefList) throws Exception {
        List<T> list = new ArrayList<>(tagAlarmDefList.size());


        String mdcTag = null;

        for (ExcelTagAlarmDef tagExcel : tagAlarmDefList) {

            if (tagExcel.rdbTag != null && !tagExcel.rdbTag.isEmpty()) {
                if (!tagExcel.rdbTag.equals(mdcTag)) {
                    mdcTag = tagExcel.rdbTag;

                }
            }

            if (mdcTag == null) {
                continue;
            }
            T plcTagType = createPlcTagDef(mdcOptions, mdcTag, tagExcel);

            list.add(plcTagType);
        }

        return list;
    }


    private T createPlcTagDef(MdcOptions mdcOptions, String mdcTag, ExcelTagAlarmDef tagExcel) throws InstantiationException, IllegalAccessException {

        T plcTagType = clz.newInstance();
        plcTagType.setActive(Boolean.TRUE);


        String prefix = mdcTag.substring(0, 2).toUpperCase();

        int tagIndex = Integer.parseInt(mdcTag.substring(2));

        plcTagType.setMdcTag(mdcTag);
        plcTagType.setTagPrefix(prefix);
        plcTagType.setTagIndex(tagIndex);

        plcTagType.setBitIndex(tagExcel.bit);


        plcTagType.setEnUs(tagExcel.enUs);
        plcTagType.setZhCN(tagExcel.zhCN);


        long objectId = PlcTagTypeIdBuilder.buildId(prefix, tagIndex, tagExcel.bit);
        plcTagType.setObjectId(objectId);
        updateArea(mdcOptions, plcTagType);
        processCreate(mdcOptions, plcTagType);
        return plcTagType;
    }

    protected void processCreate(MdcOptions mdcOptions, T plcTagType) {

    }

    protected void processUpdate(MdcOptions mdcOptions, T plcTagType) {

    }

    protected void updateArea(MdcOptions mdcOptions, T plcTagType) {
        if (plcTagType.getShop() == null) {
            plcTagType.setShop(mdcOptions.SHOP);
        }

        if (plcTagType.getArea() == null) {
            plcTagType.setArea(mdcOptions.AREA);
        }

        if (plcTagType.getSection() == null) {
            plcTagType.setSection(mdcOptions.SECTION);
        }

        if (plcTagType.getPoint() == null) {
            plcTagType.setPoint(mdcOptions.POINT);
        }
    }
}
